/*
 * TepcoMeter:TepcoMetterLogic.java
 * Copyright © 2011 ho9ho9 All Rights Reserved.
 */
package com.ho9ho9.tepcometer.logic;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.util.Log;
import android.widget.RemoteViews;

import com.ho9ho9.tepcometer.R;
import com.ho9ho9.tepcometer.db.TepcoMeterDao;
import com.ho9ho9.tepcometer.dto.HourDto;
import com.ho9ho9.tepcometer.dto.WattDto;
import com.ho9ho9.tepcometer.util.HttpUtils;

/**
 * TepcoMetterLogicクラス.
 * @author ho9ho9
 */
public class TepcoMetterLogic {

	private static final String TAG_NAME = "TepcoMetterLogic";
	private static final String JSON_DATA_URL = "http://denki.cuppat.net/data/%s.json";
	private static final DateFormat PARSE_UPDATED = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private static final DateFormat FORMAT_URL_DATE = new SimpleDateFormat("yyyyMMdd");
	private static final DateFormat WIDGET_FORMAT_UPDATED = new SimpleDateFormat("MM/dd HH:mm");
	
	public void reflectWidgetViews(Resources r, RemoteViews views, WattDto wattDto) {
		TepcoMetterLogic logic = new TepcoMetterLogic();
		// 結果から値を設定
		Integer currentWatt = wattDto.getCurrentHour().getWattValue();
		Integer calcRet = logic.calculateUseWatt(currentWatt, wattDto.getCapability());
		views.setTextViewText(R.id.useWatt, calcRet.toString());
		views.setTextViewText(R.id.updateDate, WIDGET_FORMAT_UPDATED.format(wattDto.getUpdated()));
		views.setTextViewText(R.id.currentWatt, currentWatt.toString());
		views.setTextViewText(R.id.maxWatt, wattDto.getCapability().toString());

		// グラフ描画
		drawWidgetGraph(r, views, calcRet);
	}

	private void drawWidgetGraph(Resources r, RemoteViews views, Integer calcRet) {
		TepcoMetterLogic logic = new TepcoMetterLogic();
		// グラフ描画
		Bitmap mainParts = BitmapFactory.decodeResource(r, R.drawable.w_left_parts_main);
		Bitmap bitmap = Bitmap.createBitmap(mainParts.getWidth(), mainParts.getHeight(), Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		Paint paint = new Paint();
		LinearGradient gr = new LinearGradient(
				0, calculateGraphOffset(mainParts.getHeight(), calcRet), 
				0, mainParts.getHeight(),
				logic.getWattMetterGradientColor(calcRet), null, TileMode.CLAMP);
		paint.setShader(gr);
		canvas.drawRect(0, calculateGraphOffset(mainParts.getHeight(), calcRet), mainParts.getWidth(), mainParts.getHeight(), paint);
		views.setImageViewBitmap(R.id.graphCanvasView, bitmap);
	}


	private float calculateGraphOffset(int height, Integer calcRet) {
		// 開始位置のため100（MAX）から現在の利用率を引いたものに1%分の積を求める
		return (new Float(height) / 100) * (100 - calcRet);
	}

	public int[] getWattMetterGradientColor(Integer calcRet) {
		int[] result = null;
		if (calcRet < 90) {
			result = new int[] {0xff2df86e, 0xff8ffbb2};
		} else if (calcRet < 96) {
			result = new int[] {0xffffe32a, 0xfffff3a1};
		} else {
			result = new int[] {0xffff2257, 0xffff99b1};
		}
		return result;
	}

	public Integer calculateUseWatt(Integer currentWatt, Integer capability) {
		Float calcRet = (new Float(currentWatt) / new Float(capability)) * 100;
		return Math.round(calcRet);
	}

	public WattDto getToDayWattInfo(Context context) {
		Calendar cal = getCurrentCalendar();
		// DBから該当日付情報があるか検索
		TepcoMeterDao dao = new TepcoMeterDao(context);
		WattDto result = getWattInfo(cal, dao);
		if (result == null) {
			// 前日電力情報取得
			cal.add(Calendar.DATE, -1);
			result = getWattInfo(cal, dao);
		}
		return result;
	}

	private WattDto getWattInfo(Calendar cal, TepcoMeterDao dao) {
		WattDto result = dao.getWattInfo(cal.getTime());
		if ((result == null) || isWattInfoRetry(result)) {
			// DBに登録されていないもしくはすべての値が登録されていない場合
			String jsonStr = HttpUtils.get(generateJsonDataUrl(cal));
			result = parseJsonData(jsonStr, cal);
			// 取得できた場合はDBへ登録
			if (result != null) {
				dao.registerWattInfo(result);
			}
		}
		return result;
	}

	private boolean isWattInfoRetry(WattDto wattInfo) {
		boolean result = false;
//		// 再取得するか確認（24時間分のデータ無かつ前回更新から30分経過かつ前回取得から5分経過）
//		if (wattInfo.getCurrentHour().getWattHour() != 23) {
			Calendar current = Calendar.getInstance();
			// 前回更新
			Calendar updatedCal = Calendar.getInstance();
			updatedCal.setTimeInMillis(wattInfo.getUpdated().getTime());
			updatedCal.add(Calendar.MINUTE, 30);
			Log.d(TAG_NAME, "現在：" + current.getTime() + ",Updated：" + wattInfo.getUpdated());
			if (current.compareTo(updatedCal) > 0) {
				// 前回取得
				Calendar beforeCal = Calendar.getInstance();
				beforeCal.setTimeInMillis(wattInfo.getInsertDate().getTime());
				beforeCal.add(Calendar.MINUTE, 5);
				// 比較
				result = (current.compareTo(beforeCal) > 0);
				Log.d(TAG_NAME, "現在：" + current.getTime() + ",InsertDate：" + wattInfo.getInsertDate() + ",結果：" + result);
			} else {
				result = false;
			}
//		} else {
//			result = false;
//		}
		return result;
	}

	private Calendar getCurrentCalendar() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal;
	}

	private String generateJsonDataUrl(Calendar cal) {
		return String.format(JSON_DATA_URL, FORMAT_URL_DATE.format(cal.getTime()));
	}

	private WattDto parseJsonData(String jsonStr, Calendar cal) {
		WattDto result = null;
		try {
			if ((jsonStr != null) && (jsonStr.length() > 0)) {
				result = new WattDto();
				JSONObject jsonObj = new JSONObject(jsonStr);
				result.setHours(getHours(jsonObj.getJSONArray("hours")));
				result.setCapability(parseInt(jsonObj.getString("capability")));
				result.setUpdated(parseUpdatedDate(jsonObj.getString("updated")));
				result.setWattDay(cal.getTime());
				Log.d(TAG_NAME, "整合性チェック：" + result.getCurrentHour().getWattHour() + ":" + result.getUpdated().getHours());
				if (result.getCurrentHour().getWattHour() > result.getUpdated().getHours()) {
					result = null;
				}
			}
		} catch (JSONException e) {
			Log.e(TAG_NAME, e.getMessage(), e);
		}
		return result;
	}

	private List<HourDto> getHours(JSONArray hours) throws JSONException {
		List<HourDto> result = new ArrayList<HourDto>();
		if (hours != null) {
			int i = 0;
			for (; i < hours.length(); i++) {
				HourDto h = new HourDto();
				h.setWattHour(i);
				h.setWattValue(parseInt(hours.getString(i)));
				result.add(h);
			}
			for (; i < 24; i++) {
				HourDto h = new HourDto();
				h.setWattHour(i);
				h.setWattValue(0);
				result.add(h);
			}
		}
		return result;
	}

	private Integer parseInt(String str) {
		Integer result = null;
		try {
			if (str != null) {
				result = Integer.parseInt(str, 10);
			}
		} catch (Exception e) {
			Log.e(TAG_NAME, e.getMessage(), e);
		}
		return result;
	}

	private Date parseUpdatedDate(String str) {
		Date result = null;
		try {
			if (str != null) {
				result = PARSE_UPDATED.parse(str);
			}
		} catch (ParseException e) {
			Log.e(TAG_NAME, e.getMessage(), e);
		}
		return result;
	}

	/**
	 * @param wattDto
	 * @return
	 */
	public WattDto getMorningWattDto(WattDto wattDto) {
		WattDto result = (WattDto) wattDto.clone();
		List<HourDto> morningHours = new ArrayList<HourDto>();
		for (int i = 0; i < 12; i++) {
			morningHours.add(wattDto.getHours().get(i));
		}
		result.setHours(morningHours);
		return result;
	}

	/**
	 * @param wattDto
	 * @return
	 */
	public WattDto getAfternoonWattDto(WattDto wattDto) {
		WattDto result = (WattDto) wattDto.clone();
		List<HourDto> afternoonHours = new ArrayList<HourDto>();
		for (int i = 12; i < 24; i++) {
			afternoonHours.add(wattDto.getHours().get(i));
		}
		result.setHours(afternoonHours);
		return result;
	}
}
